package com.ai;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.configs.ApiConfig;
import com.domain.InterfaceView;
import com.utils.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.*;

import java.util.*;


public class ApiTest extends TestBase {


    private static final RedisTemplate<String, Object> redisTemplate = (RedisTemplate) SpringContextUtil.getBean("redisTemplate");

    /**
     * api请求跟路径
     */
    private static String rootUrl;

    /**
     * 跟路径是否以‘/’结尾
     */
    private static boolean rooUrlEndWithSlash = false;

    /**
     * 所有公共header，会在发送请求的时候添加到http header上
     */
    private static Header[] publicHeaders;

    /**
     * 是否使用form-data传参 会在post与put方法封装请求参数用到
     */
    private static boolean requestByFormData = false;

    /**
     * 配置
     */
    private ApiConfig apiConfig;

    private String apiParam;

    private String apiHead;

    private String sysName;
    /**
     * 保存数据索引
     */
    private List<String> esList = new ArrayList<>();
    /**
     * 存放接口数据
     */
    private Set<String> interSet = new HashSet<>();

    /**
     * 所有api测试用例数据
     */
    protected List<InterfaceView> dataList = new ArrayList<InterfaceView>();
    /**
     * 存放所有执行失败的用例
     */
    protected Map<String, String> mapStr = new HashMap<>();
    /**
     * 存放接口返回值
     */
    protected Map<String, String> interMap = new HashMap<>();
    /**
     * 存放redis里面的参数
     */
    protected static List<InterfaceView> interfaceViewsList = new ArrayList<>();
    /**
     * 存放session里面的参数
     */
    protected static List<Integer> myIdList = new ArrayList<>();

    // 获取所有的用例
    public static void getRedisCases() {
        ReportUtil.log("---------------------Start obtaining test cases from Redis---------------------");
        try {
            List<InterfaceView> myList = new ArrayList<>();
            myIdList = JSON.parseArray((String) redisTemplate.opsForValue().get("idSelects"), Integer.class);
            ReportUtil.log("---------------------Set of test case IDs---------------------:" + myIdList);
            for (Integer i : myIdList) {
                String result = (String) redisTemplate.opsForValue().get("interfaceV" + i);
                myList.add(JSON.parseObject(result, InterfaceView.class));
            }
            interfaceViewsList = myList;

            logger.info("---------------------Test Case Details---------------------");
            interfaceViewsList.forEach(e -> logger.info(e.toString()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @BeforeTest
    public void readData() {
        ApiTest.getRedisCases();
        logger.info("---------------------Start test case preprocessing---------------------");
        interfaceViewsList.forEach(t -> {
            InterfaceView interfaceView = new InterfaceView();
            interfaceView.setId(t.getId());
            interfaceView.setAddress(t.getAddress());
            interfaceView.setSystems(t.getSystems());
            interfaceView.setDescrible(t.getDescrible());
            interfaceView.setErrorId(t.getErrorId());
            interfaceView.setGetOrPost(t.getGetOrPost());
            interfaceView.setHeaderId(t.getHeaderId());
            interfaceView.setIsNotOrRun(t.getIsNotOrRun());
            interfaceView.setParamId(t.getParamId());
            interfaceView.setPassOrNot(t.getPassOrNot());
            interfaceView.setResponseId(t.getResponseId());
            interfaceView.setVerifyId(t.getVerifyId());
            dataList.add(interfaceView);
        });
        logger.info("---------------------End test case preprocessing---------------------");
    }

    @DataProvider(name = "interfaceTestingCase")
    public Iterator<Object[]> getApiData(ITestContext context) {
        logger.info("---------------------Data driven loading case---------------------");
        List<Object[]> dataProvider = new ArrayList<Object[]>();
        for (InterfaceView data : dataList) {
            dataProvider.add(new Object[]{data});
        }
        logger.info("---------------------End of data-driven loading case---------------------");
        return dataProvider.iterator();
    }

    @Test(dataProvider = "interfaceTestingCase")
    public void apiTests(InterfaceView interfaceView) {

        ReportUtil.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Test case execution begins ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        logger.info("---------------------Initial information of test cases--------------------- {}", interfaceView);
        //处理请求参数问题
        String urls = interfaceView.getAddress();
        logger.info("---------------------Interface URL information---------------------: {}", urls);
        StringBuffer sb = new StringBuffer(urls);
        apiHead = interfaceView.getHeaderId();
        apiParam = interfaceView.getParamId();

        if (StrUtil.isBlank(apiHead)) {
            apiHead = "{}";
        }
        JSONObject heads = JSON.parseObject(apiHead);
        if (StrUtil.isBlank(apiParam)) {
            apiParam = "{}";
        }
        JSONObject param = JSON.parseObject(apiParam);

        logger.info("---------------------Interface request header information---------------------: {}", apiHead);
        logger.info("---------------------Interface request parameter information---------------------: {}", apiParam);
        //解析参数中的自定义函数
        //TODO

        //响应
        JSONObject httpResponse;
        String url;
        RequestUtil requestUtil = new RequestUtil();
        switch (interfaceView.getGetOrPost()) {
            case "get":
                url = assembleURL(sb, param);
                logger.info("---------------------Get the final URL information of the interface---------------------: {}", url);
                httpResponse = requestUtil.sendHttp(url, HttpRequestMethodEnum.get, heads, null);
                break;
            case "post":
                url = sb.toString();
                httpResponse = requestUtil.sendHttp(url, HttpRequestMethodEnum.post, heads, param);
                break;
            case "post_form":
                url = sb.toString();
                httpResponse = requestUtil.sendHttp(url, HttpRequestMethodEnum.post_form, heads, param);
                break;
            default:
                logger.error("---------------------Request method not supported---------------------");
                throw new RuntimeException("---------------------Request method not supported---------------------");
        }

        try {
            JSONObject expResult = JSON.parseObject(interfaceView.getVerifyId());

            if (null != httpResponse) {
                String strHttpResponse = httpResponse.toString();

                System.out.println("---------------------响应返回值--------------------- " + strHttpResponse);
                ReportUtil.log(interfaceView.getDescrible() + " 接口返回值=== " + strHttpResponse);

                boolean pass = true;
                String key = null;
                String expKeyValue = null;
                String actualKeyValue = null;
                for (String expKey : expResult.keySet()) {
                    key = expKey;
                    expKeyValue = httpResponse.getString(expKey);
                    actualKeyValue = expResult.getString(expKey);
                    if (!expKeyValue.equalsIgnoreCase(actualKeyValue)) {
                        pass = false;
                        break;
                    }
                }

                if (pass) {
                    interSet.add(strHttpResponse + "&" + "成功" + "&" + interfaceView.getId() + "&" + interfaceView.getDescrible());
                    redisTemplate.opsForValue().set("mess", JSON.toJSONString(interSet));
                } else {
                    interSet.add(strHttpResponse + "&" + "失败" + "&" + interfaceView.getId() + "&" + interfaceView.getDescrible() + ": 校验值不对，接口返回" + key + "=" + actualKeyValue + "，期望返回"  + key + "=" + expKeyValue);
                    redisTemplate.opsForValue().set("mess", JSON.toJSONString(interSet));
                }

                // 断言：验证预期信息
                for (String expKey : expResult.keySet()) {
                    key = expKey;
                    expKeyValue = httpResponse.getString(expKey);
                    actualKeyValue = expResult.getString(expKey);
                    if (expKeyValue.equalsIgnoreCase(actualKeyValue)) {
                        logger.info("校验{}，接口id：{}，接口描述：{}，校验key：{}，期望值：{}，预期值：{}","✅", interfaceView.getId(), interfaceView.getDescrible(), key, expKeyValue, actualKeyValue);
                    } else {
                        logger.info("校验{}，接口id：{}，接口描述：{}，校验key：{}，期望值：{}，预期值：{}","❌", interfaceView.getId(), interfaceView.getDescrible(), key, expKeyValue, actualKeyValue);
                    }
                    Assert.assertEquals(actualKeyValue, expKeyValue, "接口id：" + interfaceView.getId() + "校验key：" + key + "预期为：" + expKeyValue + ",实际为：" + actualKeyValue);
                }
            } else {
                interSet.add("&" + "失败" + "&" + interfaceView.getId() + "&" + interfaceView.getDescrible() + ": 接口没有调通");
                redisTemplate.opsForValue().set("mess", JSON.toJSONString(interSet));
                // 断言：验证预期信息
                Assert.assertNotNull(expResult, ": 验证预期结果失败");
            }
        } catch (Exception e) {
            ReportUtil.log(e.getMessage());
            e.printStackTrace();
        }
    }

    public String assembleURL(StringBuffer sbURL, JSONObject param) {
        if (param != null) {
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                sbURL.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
            return sbURL.toString().replaceFirst("&", "?");
        }
        return sbURL.toString();
    }


}
